package com.it.utils;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * 文件上传工具类,存储到本地
 */
@Data
@AllArgsConstructor
@Slf4j
@Component
public class RagFileUtil {

    private static final String RAG_DIRECTORY = "src/main/resources/rag";


    // 支持的文件类型常量
    public static final String TYPE_TXT = "text/plain";
    public static final String TYPE_PDF = "application/pdf";
    public static final String TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    public static final String TYPE_MARKDOWN = "text/markdown";


    /**
     * 文件上传
     * @return
     */
    public String uploadFile(byte[] bytes, String fileName) throws Exception {
        File directory = new File(RAG_DIRECTORY);
        if (!directory.exists()) {
            directory.mkdirs();
        }

        // 文件路径
        String path = Paths.get(RAG_DIRECTORY, fileName).toString();

        FileOutputStream fos = new FileOutputStream(path);
        fos.write(bytes);

        log.info("文件上传到:{}", path);
        return path;
    }

    /**
     * 提取文件内容
     * @param file 上传的文件
     * @return 文件内容
     * @throws IOException 文件读取异常
     */
    public String extractContent(MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
        String contentType = file.getContentType();
        if (contentType == null) {
            throw new IllegalArgumentException("文件类型未知");
        }

        switch (contentType) {
            case TYPE_TXT:
                return extractTxtContent(file);
            case TYPE_PDF:
                return extractPdfContent(file);
            case TYPE_DOCX:
                return extractDocxContent(file);
            case TYPE_MARKDOWN:
                return extractMarkdownContent(file);
            default:
                throw new IllegalArgumentException("不支持的文件类型: " + contentType);
        }
    }

    /**
     * 提取txt文件内容
     */
    private String extractTxtContent(MultipartFile file) throws IOException {
        return new String(file.getBytes(), StandardCharsets.UTF_8);
    }

    /**
     * 提取pdf文件内容
     */
    private String extractPdfContent(MultipartFile file) throws IOException {
        try (PDDocument pdDocument = PDDocument.load(file.getInputStream())) {
            if (pdDocument.isEncrypted()) {
                throw new IOException("文件已加密");
            }
            PDFTextStripper pdfTextStripper = new PDFTextStripper();
            return pdfTextStripper.getText(pdDocument);
        }
    }

    /**
     * 提取docx文件内容
     * @param file 上传的文件
     * @return 文件内容
     * @throws IOException 文件读取异常
     */
    private String extractDocxContent(MultipartFile file) throws IOException {
        try (InputStream is = file.getInputStream(); 
             XWPFDocument document = new XWPFDocument(is)) {

            StringBuilder content = new StringBuilder();

            for (XWPFParagraph paragraph : document.getParagraphs()) {
                content.append(paragraph.getText()).append("\n");
            }

            return content.toString().trim();
        }
    }

    /**
     * 提取markdown文件内容
     * @param file 上传的文件
     * @return 文件内容
     * @throws IOException 文件读取异常
     */
    private String extractMarkdownContent(MultipartFile file) throws IOException {
        return new String(file.getBytes(), StandardCharsets.UTF_8);
    }

    /**
     * 判断文件类型是否支持
     * @param contentType 文件类型
     * @return 是否支持
     */
    public boolean isSupportedFileType(String contentType) {
        if (contentType == null) {
            return false;
        }
        return contentType.equals(TYPE_TXT) || 
               contentType.equals(TYPE_PDF) || 
               contentType.equals(TYPE_DOCX) || 
               contentType.equals(TYPE_MARKDOWN);
    }


    /**
     * 根据文件路径获取文件
     */
    /**
     * 根据文件路径获取文件内容
     * @param filePath 文件路径
     * @return 文件内容
     * @throws Exception 文件读取异常
     */
    public String getFileByPath(String filePath) throws Exception {
        File file = new File(filePath);

        if (!file.exists()) {
            throw new Exception("文件不存在: " + filePath);
        }

        if (!file.isFile()) {
            throw new Exception("路径不是文件: " + filePath);
        }

        // 根据文件扩展名确定文件类型
        String fileName = file.getName().toLowerCase();
        String fileExtension = "";
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex > 0) {
            fileExtension = fileName.substring(lastDotIndex + 1);
        }

        try {
            switch (fileExtension) {
                case "txt":
                    return extractTxtContentFromFile(file);
                case "pdf":
                    return extractPdfContentFromFile(file);
                case "docx":
                    return extractDocxContentFromFile(file);
                case "md":
                case "markdown":
                    return extractMarkdownContentFromFile(file);
                default:
                    throw new Exception("不支持的文件类型: " + fileExtension);
            }
        } catch (IOException e) {
            throw new Exception("读取文件失败: " + e.getMessage(), e);
        }
    }

    /**
     * 从文件读取txt内容
     * @param file 文件对象
     * @return 文件内容
     * @throws IOException 文件读取异常
     */
    private String extractTxtContentFromFile(File file) throws IOException {
        return new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
    }

    /**
     * 从文件读取pdf内容
     * @param file 文件对象
     * @return 文件内容
     * @throws IOException 文件读取异常
     */
    private String extractPdfContentFromFile(File file) throws IOException {
        try (PDDocument pdDocument = PDDocument.load(file)) {
            if (pdDocument.isEncrypted()) {
                throw new IOException("PDF文件已加密，无法读取");
            }
            PDFTextStripper pdfTextStripper = new PDFTextStripper();
            return pdfTextStripper.getText(pdDocument);
        }
    }

    /**
     * 从文件读取docx内容
     * @param file 文件对象
     * @return 文件内容
     * @throws IOException 文件读取异常
     */
    private String extractDocxContentFromFile(File file) throws IOException {
        try (XWPFDocument document = new XWPFDocument(Files.newInputStream(file.toPath()))) {
            StringBuilder content = new StringBuilder();
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                content.append(paragraph.getText()).append("\n");
            }
            return content.toString().trim();
        }
    }

    /**
     * 从文件读取markdown内容
     * @param file 文件对象
     * @return 文件内容
     * @throws IOException 文件读取异常
     */
     private String extractMarkdownContentFromFile(File file) throws IOException {
         return new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
     }

    /**
     * 删除文件
     * @param filePath 文件路径
     */
    public void deleteFile(String filePath) {
        try {
            if (filePath == null || filePath.trim().isEmpty()) {
                log.warn("文件路径为空，无法删除文件");
                return;
            }

            log.info("开始删除文件，原始路径: " + filePath);
            
            File file = new File(filePath);
            
            // 如果传入的是相对路径（如：src\main\resources\rag\xxx.txt），直接使用
            if (file.exists()) {
                log.info("使用原始路径找到文件: " + file.getAbsolutePath());
            } else {
                // 如果原始路径找不到文件，尝试提取文件名并构建相对路径
                String fileName = file.getName();
                String relativePath = Paths.get(RAG_DIRECTORY, fileName).toString();
                file = new File(relativePath);
                log.info("原始路径未找到文件，尝试使用相对路径: " + relativePath);
                
                // 如果相对路径也找不到，尝试直接在当前工作目录下查找
                if (!file.exists()) {
                    // 处理Windows路径分隔符问题，将反斜杠替换为正斜杠
                    String normalizedPath = filePath.replace("\\", "/");
                    file = new File(normalizedPath);
                    log.info("尝试标准化路径: " + normalizedPath);
                }
            }

            if (file.exists()) {
                if (file.delete()) {
                    log.info("删除文件成功: " + file.getAbsolutePath());
                } else {
                    log.error("删除文件失败: " + file.getAbsolutePath());
                }
            } else {
                log.warn("文件不存在，无需删除。原路径: " + filePath + ", 最终尝试路径: " + file.getAbsolutePath());
            }
        } catch (SecurityException e) {
            log.error("删除文件时发生安全异常: " + filePath, e);
        } catch (Exception e) {
            log.error("删除文件时发生异常: " + filePath, e);
        }
    }
}
